package com.kadron.paging;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;


public class AbstractModelContainer implements ModelContainer {

	/**
	 * 
	 */
	private static final long serialVersionUID = 3634959391022293884L;
	
	private int currentPage = ModelContainer.DEFAULT_PAGE;
	private int records = ModelContainer.MAX_RECORDS;
	private int pagesMaxium = ModelContainer.PAGES_MAXIMUM;
	private int fastStep = ModelContainer.FAST_STEP;
	
	private Long count;
	private List<Integer> pages = new ArrayList<Integer>();

	private final Map<String, KRow> wrappedData = new HashMap<String, KRow>();
	private final Set<String> wrappedKeys = new HashSet<String>();
	private List<KRow> models = new LinkedList<KRow>();

	@Override
	public void clear() {
		this.records = ModelContainer.MAX_RECORDS;
		this.pagesMaxium = ModelContainer.PAGES_MAXIMUM;
		this.fastStep = ModelContainer.FAST_STEP;
		this.currentPage = ModelContainer.DEFAULT_PAGE;
		this.count = null;
		this.wrappedData.clear();
		this.wrappedKeys.clear();
		this.pages.clear();
		this.models.clear();
	}

	public AbstractModelContainer() {
		super();
	}

	public void initPages() {
		pages.clear();
		final Set<Integer> currentPages = new LinkedHashSet<Integer>();
		final int lastPage = getLast();
		final int middleValue = pagesMaxium / 2;
		final int possibleStartPage = currentPage - middleValue;
        int startPage = ModelContainer.DEFAULT_PAGE;
        int endPage = lastPage;
		if (lastPage > pagesMaxium) {
			if (possibleStartPage <= 0) {
				startPage = ModelContainer.DEFAULT_PAGE;
			} else {
				startPage = possibleStartPage;
			}
			final int possibleEndPage = startPage + pagesMaxium--;
            if (possibleEndPage > lastPage) {
                endPage = lastPage;
                startPage = endPage - pagesMaxium++;
            } else {
            	endPage = possibleEndPage;				
			}
        }
		//Collect all pages
        for (int i = startPage; i <= endPage; i++) {
        	currentPages.add(i);
        }
        pages.addAll(currentPages);
	}
	
	@Override
	public int getLast() {
		int lastPage = Long.valueOf(count/records).intValue();
		final long moduo = count % records;
		if (moduo > 0) {
			lastPage++;
		}
		return lastPage;
	}
	
	@Override
	public void wrapp(String key, KRow value) {
		wrappedData.put(key, value);
		wrappedKeys.add(key);
	}
	
	@Override
	public void unwrapp(String key) {
		Object object = wrappedData.get(key);
		if (object != null) {
			wrappedData.remove(object);
		}
		wrappedKeys.remove(key);
	}
	
	@Override
	public Collection<KRow> getWrapped() {
		return wrappedData.values();
	}

	@Override
	public int getRecords() {
		return records;
	}

	@Override
	public void setRecords(int records) {
		this.records = records;
	}

	@Override
	public int getFastStep() {
		return fastStep;
	}

	@Override
	public void setFastStep(int fastStep) {
		this.fastStep = fastStep;
	}

	@Override
	public Long getCount() {
		return count;
	}

	@Override
	public void setCount(Long count) {
		this.count = count;
	}

	@Override
	public List<Integer> getPages() {
		return pages;
	}
	
	@Override
	public int getCurrentPage() {
		return currentPage;
	}

	@Override
	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	@Override
	public List<KRow> getModels() {
		return models;
	}

	@Override
	public void setModels(List<KRow> models) {
		this.models = models;
	}

	@Override
	public Map<String, KRow> getWrappedData() {
		return wrappedData;
	}

	@Override
	public Set<String> getWrappedKeys() {
		return wrappedKeys;
	}

	@Override
	public boolean isEmpty() {
		return models.isEmpty();
	}
	
	@Override
	public boolean isPagingAvb() {
		return count != null && count > records;
	}
	
	@Override
	public boolean isFirstAvb() {
		return isPagingAvb() && currentPage > ModelContainer.DEFAULT_PAGE;
	}
	
	@Override
	public boolean isFastPrevAvb() {
		return currentPage - fastStep >= ModelContainer.DEFAULT_PAGE;
	}
	
	@Override
	public boolean isFastNextAvb() {
		return currentPage + fastStep <= getLast();
	}
	
	@Override
	public boolean isLastAvb() {
		return isPagingAvb() && currentPage < getLast();
	}
	
	@Override
	public boolean isAll() {
		return records == Integer.MAX_VALUE;
	}
	
	@Override
	public boolean isItemsAvb() {
		return count > MAX_RECORDS;
	}
}